<template>
  <div class="base-element-shape" :style="{
    top: elementInfo.top + 'px',
    left: elementInfo.left + 'px',
    width: elementInfo.width + 'px',
    height: elementInfo.height + 'px'
  }">
    <div class="rotate-wrapper" :style="{ transform: `rotate(${elementInfo.rotate}deg)` }">
      <div class="element-content" :style="{
        opacity: elementInfo.opacity,
        filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '', // 应用元素的阴影
        transform: flipStyle, // 元素的翻转样式
        color: text.defaultColor,
        fontFamily: text.defaultFontName
      }">
        <svg overflow="visible" :width="elementInfo.width" :height="elementInfo.height">
          <!-- SVG允许我们定义以后需要重复使用的图形元素。建议把所有需要再次使用的引用元素定义在defs元素里面，
            在defs元素中定义的图形元素不会直接呈现。你可以在你的视口的任意地方利用 <use>元素呈现这些元素。 -->
          <defs v-if="elementInfo.gradient">
            <!-- 图形渐变效果组件 -->
            <GradientDefs :id="`base-gradient-${elementInfo.id}`" :type="elementInfo.gradient.type"
              :color1="elementInfo.gradient.color[0]" :color2="elementInfo.gradient.color[1]"
              :rotate="elementInfo.gradient.rotate" />
          </defs>
          <!-- 元素g是用来组合对象的容器。添加到g元素的属性会被其所有的子元素继承。 -->
          <g
            :transform="`scale(${elementInfo.width / elementInfo.viewBox[0]},${elementInfo.height / elementInfo.viewBox[1]}) translate(0,0) matrix(1,0,0,1,0,0)`">
            <!-- path 元素是用来定义形状的通用元素。所有的基本形状都可以用 path 元素来创建。 -->
            <!-- vector-effect属性指明绘制对象时要使用的矢量效果。在任何其他合成操作（如滤镜，蒙版和剪辑等）之前，都要应用矢量效果
                 stroke-linecap属性制定了，在开放子路径被设置描边的情况下，用于开放自路径两端的形状
                 stroke属性定义了给定图形元素的外轮廓的颜色，它的默认值是none
                 stroke-dasharray属性可控制用来描边的点划线的图案范式
            -->
            <path vector-effect="non-scaling-stroke" stroke-linecap="butt" stroke-miterlimit="8" :d="elementInfo.path"
              :fill="elementInfo.gradient ? `url(#base-gradient-${elementInfo.id})` : elementInfo.fill"
              :stroke="outlineColor" :stroke-width="outlineWidth"
              :stroke-dasharray="outlineStyle === 'dashed' ? '10 5' : '0 0'"></path>
          </g>
        </svg>
        <!-- 形状的文本 -->
        <div class="shape-text" :class="text.align">
          <div class="ProseMirror-static" v-html="text.content"></div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { PropType, computed } from 'vue'
import { PPTShapeElement, ShapeText } from '@/types/slides'
import useElementOutline from '../hooks/useElementOutline'
import useElementShadow from '../hooks/useElementShadow'
import useElementFlip from '../hooks/useElementFlip'

import GradientDefs from './GradientDefs.vue'

// eslint-disable-next-line no-undef
const props = defineProps({
  elementInfo: {
    type: Object as PropType<PPTShapeElement>,
    required: true
  }
})
// outline：形状的轮廓
const outline = computed(() => props.elementInfo.outline)
const { outlineColor, outlineWidth, outlineStyle } = useElementOutline(outline)
// shadow：形状的阴影
const shadow = computed(() => props.elementInfo.shadow)
const { shadowStyle } = useElementShadow(shadow)
// flip：形状的翻转样式
const flipH = computed(() => props.elementInfo.flipH)
const flipV = computed(() => props.elementInfo.flipV)
const { flipStyle } = useElementFlip(flipH, flipV)
// text：形状的文本内容及样式
const text = computed<ShapeText>(() => {
  const defaultText: ShapeText = {
    content: '',
    defaultFontName: '微软雅黑',
    defaultColor: '#000',
    align: 'middle'
  }
  if (!props.elementInfo.text) return defaultText
  return props.elementInfo.text
})
</script>

<style lang="scss" scoped>
.base-element-shape {
  position: absolute;
}

.rotate-wrapper {
  width: 100%;
  height: 100%;
}

.element-content {
  width: 100%;
  height: 100%;
  position: relative;

  svg {
    transform-origin: 0 0;
    overflow: visible;
  }
}

.shape-text {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  padding: 10px;
  line-height: 1.2;
  word-break: break-word;

  &.top {
    justify-content: flex-start;
  }

  &.middle {
    justify-content: center;
  }

  &.bottom {
    justify-content: flex-end;
  }
}
</style>